﻿' ----------------------------------------------------------------------------------
' Microsoft Developer & Platform Evangelism
' 
' Copyright (c) Microsoft Corporation. All rights reserved.
' 
' THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
' OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ----------------------------------------------------------------------------------
' The example companies, organizations, products, domain names,
' e-mail addresses, logos, people, places, and events depicted
' herein are fictitious.  No association with any real company,
' organization, product, domain name, email address, logo, person,
' places, or events is intended or should be inferred.
' ----------------------------------------------------------------------------------

Imports System.Net
Imports System.ServiceModel.Web
Imports Microsoft.Samples.WindowsPhoneCloud.Web.Models
Imports Microsoft.WindowsAzure
Imports Microsoft.WindowsAzure.StorageClient

Namespace Infrastructure
#If ACS Then
	Public Class UserTablesServiceContext
		Inherits TableServiceContext
		Implements IPushUserEndpointsRepository, IUserPrivilegesRepository, IUserRepository
		Public Const UserTableName As String = "Users"
#Else
    Public Class UserTablesServiceContext
        Inherits TableServiceContext
        Implements IPushUserEndpointsRepository, IUserPrivilegesRepository
#End If
        Public Const PushUserTableName As String = "PushUserEndpoints"

        Public Const UserPrivilegeTableName As String = "UserPrivileges"

        Private Const PublicUserId As String = "00000000-0000-0000-0000-000000000000"

        Public Sub New()
            Me.New(CloudStorageAccount.FromConfigurationSetting("DataConnectionString"))
        End Sub

        Public Sub New(ByVal account As CloudStorageAccount)
            Me.New(account.TableEndpoint.ToString(), account.Credentials)
        End Sub

        Public Sub New(ByVal baseAddress As String, ByVal credentials As StorageCredentials)
            MyBase.New(baseAddress, credentials)
            Me.IgnoreResourceNotFoundException = True
            Me.IgnoreMissingProperties = True
        End Sub

        Public ReadOnly Property PushUserEndpoints() As IQueryable(Of PushUserEndpoint)
            Get
                Return Me.CreateQuery(Of PushUserEndpoint)(PushUserTableName)
            End Get
        End Property

        Public ReadOnly Property UserPrivileges() As IQueryable(Of UserPrivilege)
            Get
                Return Me.CreateQuery(Of UserPrivilege)(UserPrivilegeTableName)
            End Get
        End Property

#If ACS Then
    Public ReadOnly Property Users() As IQueryable(Of User)
        Get
            Return Me.CreateQuery(Of User)(UserTableName)
        End Get
    End Property

        Public Sub CreateUser(ByVal userId As String, ByVal userName As String, ByVal email As String) Implements IUserRepository.CreateUser
            If Me.Users.Where(Function(u) u.UserId.Equals(userId, StringComparison.OrdinalIgnoreCase) OrElse u.Email.Equals(email, StringComparison.OrdinalIgnoreCase)).AsEnumerable().FirstOrDefault() IsNot Nothing Then
                Throw New WebFaultException(Of String)("A user with the same id or email already exists.", HttpStatusCode.BadRequest)
            End If
            Me.AddObject(UserTableName, New User With {.UserId = userId, .Name = userName, .Email = email})

            Me.SaveChanges()
        End Sub

        Public Function GetAllUsers() As IEnumerable(Of User) Implements IUserRepository.GetAllUsers
            Return Me.Users.ToList()
        End Function

        <CLSCompliant(False)>
        Public Function GetUser(ByVal userId As String) As User Implements IUserRepository.GetUser
            Return Me.Users.Where(Function(u) u.UserId.Equals(userId, StringComparison.OrdinalIgnoreCase)).AsEnumerable().FirstOrDefault()
        End Function

        <CLSCompliant(False)>
        Public Function GetUserByEmail(ByVal email As String) As User
            Return Me.Users.Where(Function(u) u.Email.Equals(email, StringComparison.OrdinalIgnoreCase)).AsEnumerable().FirstOrDefault()
        End Function

        Public Function UserExists(ByVal userId As String) As Boolean Implements IUserRepository.UserExists
            Return Me.GetUser(userId) IsNot Nothing
        End Function
#End If

        Public Sub AddPushUserEndpoint(ByVal pushUserEndpoint As PushUserEndpoint) Implements IPushUserEndpointsRepository.AddPushUserEndpoint
            Me.AddObject(PushUserTableName, pushUserEndpoint)

            Me.SaveChanges()
        End Sub

        <CLSCompliant(False)> _
        Public Sub RemovePushUserEndpoint(ByVal pushUserEndpointData As PushUserEndpoint) Implements IPushUserEndpointsRepository.RemovePushUserEndpoint
            Dim pushUserEndpoint = Me.GetPushUserByApplicationAndDevice(pushUserEndpointData.PartitionKey, pushUserEndpointData.RowKey)

            Me.DeleteObject(pushUserEndpoint)

            Me.SaveChanges()
        End Sub

        Public Function GetAllPushUsers() As IEnumerable(Of String) Implements IPushUserEndpointsRepository.GetAllPushUsers
            Return Me.PushUserEndpoints.ToList().GroupBy(Function(u) u.UserId).Select(Function(g) g.Key)
        End Function

        Public Function GetPushUsersByName(ByVal userId As String) As IEnumerable(Of PushUserEndpoint) Implements IPushUserEndpointsRepository.GetPushUsersByName
            Return Me.PushUserEndpoints.Where(Function(u) u.UserId.Equals(userId, StringComparison.OrdinalIgnoreCase)).AsEnumerable()
        End Function

        Public Function GetPushUserByApplicationAndDevice(ByVal applicationId As String, ByVal deviceId As String) As PushUserEndpoint Implements IPushUserEndpointsRepository.GetPushUserByApplicationAndDevice
            Return (Me.PushUserEndpoints.Where(Function(u) u.PartitionKey.Equals(applicationId, StringComparison.OrdinalIgnoreCase) AndAlso u.RowKey.Equals(deviceId, StringComparison.OrdinalIgnoreCase)).FirstOrDefault())
        End Function

        <CLSCompliant(False)>
        Public Sub UpdatePushUserEndpoint(ByVal pushUserEndpoint As PushUserEndpoint) Implements IPushUserEndpointsRepository.UpdatePushUserEndpoint
            Me.UpdateObject(pushUserEndpoint)

            Me.SaveChanges()
        End Sub

        Public Function GetUsersWithPrivilege(ByVal privilege As String) As IEnumerable(Of UserPrivilege) Implements IUserPrivilegesRepository.GetUsersWithPrivilege
            Return Me.UserPrivileges.Where(Function(p) p.Privilege.Equals(privilege, StringComparison.OrdinalIgnoreCase)).AsEnumerable()
        End Function

        Public Sub AddPrivilegeToUser(ByVal userId As String, ByVal privilege As String) Implements IUserPrivilegesRepository.AddPrivilegeToUser
            If Not Me.HasUserPrivilege(userId, privilege) Then
                Me.AddObject(UserPrivilegeTableName, New UserPrivilege With {.UserId = userId, .Privilege = privilege})

                Me.SaveChanges()
            End If
        End Sub

        Public Sub AddPublicPrivilege(ByVal privilege As String) Implements IUserPrivilegesRepository.AddPublicPrivilege
            Me.AddPrivilegeToUser(PublicUserId, privilege)
        End Sub

        Public Sub RemovePrivilegeFromUser(ByVal userId As String, ByVal privilege As String) Implements IUserPrivilegesRepository.RemovePrivilegeFromUser
            Dim userPrivilege = Me.GetUserPrivilege(userId, privilege)
            If userPrivilege IsNot Nothing Then
                Me.DeleteObject(userPrivilege)

                Me.SaveChanges()
            End If
        End Sub

        Public Sub DeletePublicPrivilege(ByVal privilege As String) Implements IUserPrivilegesRepository.DeletePublicPrivilege
            Me.RemovePrivilegeFromUser(PublicUserId, privilege)
        End Sub

        Public Function HasUserPrivilege(ByVal userId As String, ByVal privilege As String) As Boolean Implements IUserPrivilegesRepository.HasUserPrivilege
            Return Me.GetUserPrivilege(userId, privilege) IsNot Nothing
        End Function

        Public Function PublicPrivilegeExists(ByVal privilege As String) As Boolean Implements IUserPrivilegesRepository.PublicPrivilegeExists
            Return Me.HasUserPrivilege(PublicUserId, privilege)
        End Function

        Public Sub DeletePrivilege(ByVal privilege As String) Implements IUserPrivilegesRepository.DeletePrivilege
            Dim userPrivileges = Me.GetUsersWithPrivilege(privilege)
            For Each userPrivilege In userPrivileges
                Me.DeleteObject(userPrivilege)
            Next userPrivilege

            Me.SaveChanges()
        End Sub

        Private Function GetUserPrivilege(ByVal userId As String, ByVal privilege As String) As UserPrivilege
            Return Me.UserPrivileges.Where(Function(p) p.UserId.Equals(userId, StringComparison.OrdinalIgnoreCase) AndAlso p.Privilege.Equals(privilege, StringComparison.OrdinalIgnoreCase)).AsEnumerable().FirstOrDefault()
        End Function
    End Class
End Namespace